package com.scedu.utils;



import com.scedu.entity.Payload;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;


import javax.crypto.SecretKey;

import java.util.Date;
import java.util.Map;

/**

        * 生成token以及校验token相关方法
        */
public class JwtUtil {

    private static final String JWT_PAYLOAD_USER_KEY = "user";



    /**
     * 私钥加密token
     *
     * @param userInfo   载荷中的数据
     * @param secretKey  秘钥
     * @param tokenExpireTime     过期时间，单位秒
     * @return JWT
     */
    public static String generateTokenExpireInSeconds(Object userInfo, String secretKey, Long tokenExpireTime) {
        Long currentTimeMillis=System.currentTimeMillis();
        Date expireDate = new Date(currentTimeMillis + tokenExpireTime * 1000*60);
        byte[] keyBytes = secretKey.getBytes();
        SecretKey key = Keys.hmacShaKeyFor(keyBytes);


        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toString(userInfo))
                .setExpiration(expireDate)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }
    /**
     * 公钥解析token
     *
     * @param token     用户请求中的token
     * @param secretKey 公钥
     * @return Jws<Claims>
     */
    private static Jws<Claims> parserToken(String token,  String secretKey) {
        return Jwts.parserBuilder().setSigningKey(secretKey.getBytes()).build().parseClaimsJws(token);
    }
    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param secretKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, String secretKey, Class<T> userType) {
        Jws<Claims> claimsJws = parserToken(token, secretKey);
        Claims body = claimsJws.getBody();
        Payload<T> claims = new Payload<>();
        claims.setId(body.getId());
        claims.setUserInfo(JsonUtil.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType));
        claims.setExpiration(body.getExpiration());
        return claims;
    }
    /**
     * 从token中获取claim
     *
     * @param token token
     * @return claim
     */
    public static Claims getClaimsFromToken(String token,  String secretKey) {
        try {
            return Jwts.parserBuilder()
                    .setSigningKey(secretKey.getBytes())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
            //log.error("token解析错误", e);
            throw new IllegalArgumentException("Token invalided.");
        }
    }

    /**
     * 获取token的过期时间
     *
     * @param token token
     * @return 过期时间
     */
    public static Date getExpirationDateFromToken(String token,  String secretKey) {
        return getClaimsFromToken(token,secretKey)
                .getExpiration();
    }

    /**
     * 判断token是否过期
     *
     * @param token token
     * @return 已过期返回true，未过期返回false
     */
    public static Boolean isTokenExpired(String token,  String secretKey) {
        Date expiration = getExpirationDateFromToken(token,secretKey);
        return expiration.before(new Date());
    }



    /**
     * 为指定用户生成token
     *
     * @param claims 用户信息
     * @return token
     */
    public static String generateToken(Map<String, Object> claims,  String secretKey, int tokenExpireTime) {
        Date createdTime = new Date();
        Long currentTimeMillis=System.currentTimeMillis();
        Date expirationTime = new Date(currentTimeMillis + tokenExpireTime * 1000*60);



        byte[] keyBytes = secretKey.getBytes();
        SecretKey key = Keys.hmacShaKeyFor(keyBytes);

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(createdTime)
                .setExpiration(expirationTime)
                // 你也可以改用你喜欢的算法
                // 支持的算法详见：https://github.com/jwtk/jjwt#features
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 判断token是否非法
     *
     * @param token token
     * @return 未过期返回true，否则返回false
     */
    public static Boolean validateToken(String token,  String secretKey) {
        return !isTokenExpired(token,secretKey);
    }

}
